home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 June: Reference Library / Dev.CD Jun 95 / Dev.CD Jun 95.toast / What's New? / New System Software Extensions / QuickDraw 3D ß / Programming / SampleCode / BoxTex / BoxTex3DSupport.c < prev    next >
Encoding:
Text File  |  1995-04-20  |  15.6 KB  |  582 lines  |  [TEXT/MPCC]

  1. // My3dSupport.c - QuickDraw 3d routines
  2. //
  3. // This file contains utility routines for QuickDraw 3d sample code.
  4. // This app shows how to apply a exture shader to an object.  Bear in
  5. // mind that any object that you wish to texture map needs to have
  6. // UV parameters applied.
  7. //
  8. // Created 27th Dec 1994, Nick Thompson, DEVSUPPORT
  9. //
  10.  
  11. #include <QuickDraw.h>
  12. #include <QDOffScreen.h>
  13. #include <Files.h>
  14.  
  15.  
  16. #include "BoxTex3DSupport.h"
  17.  
  18.  
  19. #include "QD3DDrawContext.h"
  20. #include "QD3DRenderer.h"
  21. #include "QD3DShader.h"
  22. #include "QD3DCamera.h"
  23. #include "QD3DLight.h"
  24. #include "QD3DGeometry.h"
  25. #include "QD3DGroup.h"
  26. #include "QD3DMath.h"
  27. #include "QD3DSet.h"
  28. #include "QD3DTransform.h"
  29.  
  30. #include "Textures.h"
  31.  
  32.  
  33. static     TQ3Point3D    documentGroupCenter;
  34. static    float        documentGroupScale;
  35.  
  36.  
  37. static    TQ3FileObject         MyGetNewFile( FSSpec *myFSSpec, TQ3Boolean *isText ) ;
  38.  
  39. void GetGroupBBox(
  40.     DocumentPtr            theDocument,
  41.     TQ3BoundingBox         *viewBBox) ;
  42.                                                 
  43. static    TQ3Status MyAddShaderToGroup( TQ3GroupObject group ) ;
  44.  
  45. static TQ3Status GetDocumentGroupBoundingBox( 
  46.     DocumentPtr theDocument , 
  47.     TQ3BoundingBox *viewBBox) ;
  48.  
  49. //----------------------------------------------------------------------------------
  50. // attach a shader to the group
  51.  
  52. static TQ3Status MyAddShaderToGroup( TQ3GroupObject group )
  53. {
  54. //    TQ3ShaderObject    illuminationShader = Q3PhongIllumination_New();
  55.     TQ3ShaderObject    illuminationShader = Q3LambertIllumination_New();
  56.  
  57.     Q3Group_AddObject(group, illuminationShader);
  58.     Q3Object_Dispose(illuminationShader);
  59.     return(kQ3Success);
  60. }
  61.  
  62. TQ3ViewObject MyNewView(WindowPtr theWindow)
  63. {
  64.     TQ3Status                myStatus;
  65.     TQ3ViewObject            myView;
  66.     TQ3DrawContextObject        myDrawContext;
  67.     TQ3RendererObject        myRenderer;
  68.     TQ3CameraObject            myCamera;
  69.     TQ3GroupObject            myLights;
  70.     
  71.     myView = Q3View_New();
  72.     
  73.     //    Create and set draw context.
  74.     if ((myDrawContext = MyNewDrawContext(theWindow)) == nil )
  75.         goto bail;
  76.         
  77.     if ((myStatus = Q3View_SetDrawContext(myView, myDrawContext)) == kQ3Failure )
  78.         goto bail;
  79.  
  80.     Q3Object_Dispose( myDrawContext ) ;
  81.     
  82.     //    Create and set renderer.
  83.     
  84.     
  85.     
  86.     // this would use the wireframe renderer
  87. #if 0
  88.     myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeWireFrame);
  89.     if ((myStatus = Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) {
  90.         goto bail;
  91.     }
  92. #else
  93.     // this would use the interactive software renderer
  94.  
  95.     if ((myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeInteractive)) != nil ) {
  96.         if ((myStatus = Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) {
  97.             goto bail;
  98.         }
  99.     }
  100.     else {
  101.         goto bail;
  102.     }
  103. #endif
  104.  
  105.     Q3Object_Dispose( myRenderer ) ;
  106.     
  107.     //    Create and set camera.
  108.     if ( (myCamera = MyNewCamera(theWindow)) == nil )
  109.         goto bail;
  110.         
  111.     if ((myStatus = Q3View_SetCamera(myView, myCamera)) == kQ3Failure )
  112.         goto bail;
  113.  
  114.     Q3Object_Dispose( myCamera ) ;
  115.     
  116.     //    Create and set lights.
  117.     if ((myLights = MyNewLights()) == nil )
  118.         goto bail;
  119.         
  120.     if ((myStatus = Q3View_SetLightGroup(myView, myLights)) == kQ3Failure )
  121.         goto bail;
  122.         
  123.     Q3Object_Dispose(myLights);
  124.  
  125.     //    Done!!!
  126.     return ( myView );
  127.     
  128. bail:
  129.     //    If any of the above failed, then don't return a view.
  130.     return ( nil );
  131. }
  132.  
  133. //----------------------------------------------------------------------------------
  134.  
  135. TQ3DrawContextObject MyNewDrawContext(WindowPtr theWindow)
  136. {
  137.     TQ3DrawContextData        myDrawContextData;
  138.     TQ3MacDrawContextData    myMacDrawContextData;
  139.     TQ3ColorARGB            ClearColor;
  140.     TQ3DrawContextObject    myDrawContext ;
  141.     
  142.     //    Set the background color.
  143.     ClearColor.a = 1.0;
  144.     ClearColor.r = 1.0;
  145.     ClearColor.g = 1.0;
  146.     ClearColor.b = 1.0;
  147.     
  148.     //    Fill in draw context data.
  149.     myDrawContextData.clearImageMethod = kQ3ClearMethodWithColor;
  150.     myDrawContextData.clearImageColor = ClearColor;
  151.     myDrawContextData.paneState = kQ3False;
  152.     myDrawContextData.maskState = kQ3False;
  153.     myDrawContextData.doubleBufferState = kQ3True;
  154.  
  155.     myMacDrawContextData.drawContextData = myDrawContextData;
  156.     
  157.     myMacDrawContextData.window = (CGrafPtr) theWindow;        // this is the window associated with the view
  158.     myMacDrawContextData.library = kQ3Mac2DLibraryNone;
  159.     myMacDrawContextData.viewPort = nil;
  160.     myMacDrawContextData.grafPort = nil;
  161.     
  162.     //    Create draw context and return it, if it’s nil the caller must handle
  163.     myDrawContext = Q3MacDrawContext_New(&myMacDrawContextData) ;
  164.  
  165.     return myDrawContext ;
  166. }
  167.  
  168. //----------------------------------------------------------------------------------
  169.  
  170. TQ3CameraObject MyNewCamera(WindowPtr theWindow)
  171. {
  172.     TQ3ViewAngleAspectCameraData    perspectiveData;
  173.     TQ3CameraObject                camera;
  174.     
  175.     TQ3Point3D                     from     = { 0.0, 0.0, 13.0 };
  176.     TQ3Point3D                     to         = { 0.0, 0.0, 0.0 };
  177.     TQ3Vector3D                 up         = { 0.0, 1.0, 0.0 };
  178.  
  179.     float                         fieldOfView = 1;
  180.     float                         hither         =  0.001;
  181.     float                         yon         =  1000;
  182.     
  183.     TQ3Status                    returnVal = kQ3Failure ;
  184.  
  185.  
  186.     perspectiveData.cameraData.placement.cameraLocation     = from;
  187.     perspectiveData.cameraData.placement.pointOfInterest     = to;
  188.     perspectiveData.cameraData.placement.upVector             = up;
  189.  
  190.     perspectiveData.cameraData.range.hither    = hither;
  191.     perspectiveData.cameraData.range.yon     = yon;
  192.  
  193.     perspectiveData.cameraData.viewPort.origin.x = -1.0;
  194.     perspectiveData.cameraData.viewPort.origin.y = 1.0;
  195.     perspectiveData.cameraData.viewPort.width = 2.0;
  196.     perspectiveData.cameraData.viewPort.height = 2.0;
  197.     
  198.     perspectiveData.fov                = fieldOfView;
  199.     perspectiveData.aspectRatioXToY    =
  200.         (float) (theWindow->portRect.right - theWindow->portRect.left) / 
  201.         (float) (theWindow->portRect.bottom - theWindow->portRect.top);
  202.         
  203.     camera = Q3ViewAngleAspectCamera_New(&perspectiveData);
  204.  
  205.     return camera ;
  206. }
  207.  
  208.  
  209. //----------------------------------------------------------------------------------
  210.  
  211. TQ3GroupObject MyNewLights()
  212. {
  213.     TQ3GroupPosition            myGroupPosition;
  214.     TQ3GroupObject            myLightList;
  215.     TQ3LightData                myLightData;
  216.     TQ3PointLightData        myPointLightData;
  217.     TQ3DirectionalLightData    myDirectionalLightData;
  218.     TQ3LightObject            myAmbientLight, myPointLight, myFillLight;
  219.     TQ3Point3D                pointLocation = { -10.0, 0.0, 10.0 };
  220.     TQ3Vector3D                fillDirection = { 10.0, 0.0, 10.0 };
  221.     TQ3ColorRGB                WhiteLight = { 1.0, 1.0, 1.0 };
  222.     
  223.     //    Set up light data for ambient light.  This light data will be used for point and fill
  224.     //    light also.
  225.  
  226.     myLightData.isOn = kQ3True;
  227.     myLightData.color = WhiteLight;
  228.     
  229.     //    Create ambient light.
  230.     myLightData.brightness = .2;
  231.     myAmbientLight = Q3AmbientLight_New(&myLightData);
  232.     if ( myAmbientLight == nil )
  233.         goto bail;
  234.     
  235.     //    Create point light.
  236.     myLightData.brightness = 1.0;
  237.     myPointLightData.lightData = myLightData;
  238.     myPointLightData.castsShadows = kQ3False;
  239.     myPointLightData.attenuation = kQ3AttenuationTypeNone;
  240.     myPointLightData.location = pointLocation;
  241.     myPointLight = Q3PointLight_New(&myPointLightData);
  242.     if ( myPointLight == nil )
  243.         goto bail;
  244.  
  245.     //    Create fill light.
  246.     myLightData.brightness = .2;
  247.     myDirectionalLightData.lightData = myLightData;
  248.     myDirectionalLightData.castsShadows = kQ3False;
  249.     myDirectionalLightData.direction = fillDirection;
  250.     myFillLight = Q3DirectionalLight_New(&myDirectionalLightData);
  251.     if ( myFillLight == nil )
  252.         goto bail;
  253.  
  254.     //    Create light group and add each of the lights into the group.
  255.     myLightList = Q3LightGroup_New();
  256.     if ( myLightList == nil )
  257.         goto bail;
  258.     myGroupPosition = Q3Group_AddObject(myLightList, myAmbientLight);
  259.     if ( myGroupPosition == 0 )
  260.         goto bail;
  261.     myGroupPosition = Q3Group_AddObject(myLightList, myPointLight);
  262.     if ( myGroupPosition == 0 )
  263.         goto bail;
  264.     myGroupPosition = Q3Group_AddObject(myLightList, myFillLight);
  265.     if ( myGroupPosition == 0 )
  266.         goto bail;
  267.  
  268.     Q3Object_Dispose( myAmbientLight ) ;
  269.     Q3Object_Dispose( myPointLight ) ;
  270.     Q3Object_Dispose( myFillLight ) ;
  271.  
  272.     //    Done!
  273.     return ( myLightList );
  274.     
  275. bail:
  276.     //    If any of the above failed, then return nothing!
  277.     return ( nil );
  278. }
  279.  
  280.  
  281. static TQ3GroupPosition MyAddTransformedObjectToGroup( TQ3GroupObject theGroup, TQ3Object theObject, TQ3Vector3D *translation )
  282. {
  283.     TQ3TransformObject    transform;
  284.  
  285.     transform = Q3TranslateTransform_New(translation);
  286.     Q3Group_AddObject(theGroup, transform);    
  287.     Q3Object_Dispose(transform);
  288.     return Q3Group_AddObject(theGroup, theObject);    
  289. }
  290.  
  291. TQ3GroupObject MyNewModel()
  292. {
  293.     TQ3GroupObject            myGroup = NULL;
  294.     TQ3GeometryObject        myBox;
  295.     TQ3BoxData                myBoxData;
  296.     TQ3GroupPosition            myGroupPosition;
  297.     TQ3ShaderObject            myIlluminationShader ;
  298.     TQ3Vector3D                translation;
  299.     
  300.     TQ3SetObject            faces[6] ;
  301.     short                    face ;
  302.             
  303.     if ((myGroup = Q3DisplayGroup_New()) != NULL ) {
  304.         
  305.         MyAddShaderToGroup( myGroup ) ;
  306.     
  307.         // Define a shading type for the group
  308.         // and add the shader to the group
  309.     
  310.         myIlluminationShader = Q3PhongIllumination_New();
  311.         Q3Group_AddObject(myGroup, myIlluminationShader);
  312.  
  313.         myBoxData.boxAttributeSet = nil;
  314.         myBoxData.faceAttributeSet = nil;
  315.         
  316.         // create the box itself
  317.         Q3Point3D_Set(&myBoxData.origin, 0, 0, 0);
  318.         Q3Vector3D_Set(&myBoxData.orientation, 0, 1, 0);
  319.         Q3Vector3D_Set(&myBoxData.majorAxis, 0, 0, 1);    
  320.         Q3Vector3D_Set(&myBoxData.minorAxis, 1, 0, 0);    
  321.         myBox = Q3Box_New(&myBoxData);
  322.         
  323.         // put four copies of the box into the group, each one with its own translation
  324.         translation.x = 0;translation.y = 0;translation.z = 0;
  325.         MyAddTransformedObjectToGroup( myGroup, myBox, &translation ) ;
  326.     }
  327.     
  328.     TextureGroup( myGroup ) ;
  329.  
  330.     // dispose of the objects we created here
  331.     if( myIlluminationShader ) 
  332.         Q3Object_Dispose(myIlluminationShader);    
  333.                 
  334.     if( myBox ) 
  335.         Q3Object_Dispose( myBox );
  336.     
  337.     //    Done!
  338.     return ( myGroup );
  339. }
  340.  
  341.  
  342.  
  343. //-----------------------------------------------------------------------------------------------
  344. // Submit the scene for rendering/fileIO and picking
  345. TQ3Status SubmitScene( DocumentPtr theDocument ) 
  346. {        
  347.     TQ3Vector3D                globalScale;
  348.     TQ3Vector3D                globalTranslate;
  349.     
  350.     globalScale.x = globalScale.y = globalScale.z = theDocument->fGroupScale;
  351.     globalTranslate = *(TQ3Vector3D *)&theDocument->fGroupCenter;
  352.     Q3Vector3D_Scale(&globalTranslate, -1, &globalTranslate);
  353.     Q3Style_Submit(theDocument->fInterpolation, theDocument->fView);
  354.     Q3Style_Submit(theDocument->fBackFacing , theDocument->fView);
  355.     Q3Style_Submit(theDocument->fFillStyle, theDocument->fView);
  356.         
  357.     Q3MatrixTransform_Submit( &theDocument->fRotation, theDocument->fView);
  358.         
  359.     Q3ScaleTransform_Submit(&globalScale, theDocument->fView);
  360.     Q3TranslateTransform_Submit(&globalTranslate, theDocument->fView);
  361.     Q3DisplayGroup_Submit( theDocument->fModel, theDocument->fView);
  362.     
  363.     return kQ3Success ;
  364. }
  365.  
  366. //-----------------------------------------------------------------------------------------------
  367.  
  368. static TQ3Status GetDocumentGroupBoundingBox( 
  369.     DocumentPtr theDocument , 
  370.     TQ3BoundingBox *viewBBox)
  371. {
  372.     TQ3Status        status;
  373.     TQ3ViewStatus    viewStatus ;
  374.     
  375.     status = Q3View_StartBoundingBox( theDocument->fView, kQ3ComputeBoundsApproximate );
  376.     do {
  377.         status = SubmitScene( theDocument ) ;
  378.     } while((viewStatus = Q3View_EndBoundingBox( theDocument->fView, viewBBox )) == kQ3ViewStatusRetraverse );
  379.     return status ;
  380. }
  381.  
  382.  
  383. //----------------------------------------------------------------------------------
  384. void GetGroupBBox(
  385.     DocumentPtr            theDocument,
  386.     TQ3BoundingBox         *viewBBox)
  387. {
  388.     TQ3Point3D                     from     = { 0.0, 0.0, 1.0 };
  389.     TQ3Point3D                     to         = { 0.0, 0.0, 0.0 };
  390.     TQ3Vector3D                 up         = { 0.0, 1.0, 0.0 };
  391.     
  392.     float                         fieldOfView = .52359333333;
  393.     float                         hither         =  0.5;
  394.     float                         yon         =  1.5;
  395.     TQ3GroupObject                mainGroup = theDocument->fModel ;
  396.  
  397.     TQ3Status                    status;
  398.     
  399. #ifdef BETA_1_BUILD
  400.     Q3View_StartBounds( theDocument->fView );
  401.  
  402.     status = Q3DisplayGroup_BoundingBox(mainGroup, 
  403.                                         viewBBox, 
  404.                                         kQ3ComputeBoundsApproximate,
  405.                                          viewObject);
  406.  
  407.     Q3View_EndBounds( theDocument->fView );
  408. #else
  409.     status = GetDocumentGroupBoundingBox( theDocument , viewBBox) ;
  410. #endif
  411.                                         
  412.     //
  413.     //  If we have a point model, then the "viewBBox" would end up
  414.     //  being a "singularity" at the location of the point.  As
  415.     //  this bounding "box" is used in setting up the camera spec,
  416.     //  we get bogus input into Escher.
  417.     
  418.     {
  419.          float        xSize, ySize, zSize;
  420.         
  421.         xSize = viewBBox->max.x - viewBBox->min.x;
  422.         ySize = viewBBox->max.y - viewBBox->min.y;
  423.         zSize = viewBBox->max.z - viewBBox->min.z;
  424.  
  425.         if (xSize <= kQ3RealZero &&
  426.             ySize <= kQ3RealZero &&
  427.             zSize <= kQ3RealZero) {
  428.             
  429.             viewBBox->max.x += 0.0001;
  430.             viewBBox->max.y += 0.0001;
  431.             viewBBox->max.z += 0.0001;
  432.             
  433.             viewBBox->min.x -= 0.0001;
  434.             viewBBox->min.y -= 0.0001;
  435.             viewBBox->min.z -= 0.0001;
  436.         }
  437.     }
  438. }
  439.  
  440.  
  441.  
  442.  
  443. //------------------------------------------------------------------------
  444.  
  445.  
  446. TQ3Point3D AdjustCamera(
  447.     DocumentPtr            theDocument,
  448.     short                winWidth,
  449.     short                winHeight)
  450. {
  451.     float                         fieldOfView;
  452.     float                         hither;
  453.     float                         yon;
  454.     TQ3CameraPlacement            placement;
  455.     TQ3CameraRange                range;
  456.     TQ3BoundingBox                 viewBBox;
  457.     long                         fromAxis;    
  458.     float                         maxDimension;
  459.      float                        xSize, ySize, zSize;
  460.     float                        weights[2] = { 0.5, 0.5 };
  461.     TQ3Point3D                    points[2];
  462.     TQ3Vector3D                     viewVector;
  463.     TQ3Vector3D                    normViewVector;
  464.     TQ3Vector3D                    eyeToFrontClip;
  465.     TQ3Vector3D                    eyeToBackClip;
  466.     float                        viewDistance;
  467.     TQ3Vector3D                    diagonalVector;
  468.     float                        ratio;
  469.     TQ3CameraObject                camera;
  470.     
  471.     TQ3ViewObject                theView = theDocument->fView ;
  472.     TQ3GroupObject                mainGroup = theDocument->fModel ;
  473.     
  474.     TQ3Point3D                    *documentGroupCenter = &theDocument->fGroupCenter ;
  475.     float                        *documentGroupScale  = &theDocument->fGroupScale ;
  476.  
  477.     Q3View_GetCamera( theView, &camera);
  478.     GetGroupBBox( theDocument, &viewBBox);
  479.  
  480.     /*
  481.      *  If we have a point model, then the "viewBBox" would end up
  482.      *  being a "singularity" at the location of the point.  As
  483.      *  this bounding "box" is used in setting up the camera spec,
  484.      *  we get bogus input into Escher.
  485.      */
  486.     xSize = viewBBox.max.x - viewBBox.min.x;
  487.     ySize = viewBBox.max.y - viewBBox.min.y;
  488.     zSize = viewBBox.max.z - viewBBox.min.z;
  489.  
  490.     if (xSize <= kQ3RealZero &&
  491.         ySize <= kQ3RealZero &&
  492.         zSize <= kQ3RealZero)  {
  493.         viewBBox.max.x += 0.0001;
  494.         viewBBox.max.y += 0.0001;
  495.         viewBBox.max.z += 0.0001;
  496.         
  497.         viewBBox.min.x -= 0.0001;
  498.         viewBBox.min.y -= 0.0001;
  499.         viewBBox.min.z -= 0.0001;
  500.     }
  501.  
  502.     points[0] = viewBBox.min;
  503.     points[1] = viewBBox.max;
  504.  
  505.     Q3Point3D_AffineComb(points, weights, 2, documentGroupCenter);
  506.  
  507.     /*
  508.      *  The "from" point is on a vector perpendicular to the plane
  509.      *  in which the bounding box has greatest dimension.  As "up" is
  510.      *  always in the positive y direction, look at x and z directions.
  511.      */
  512.     xSize = viewBBox.max.x - viewBBox.min.x;
  513.     zSize = viewBBox.max.z - viewBBox.min.z;
  514.     
  515.     if (xSize > zSize) {
  516.         fromAxis = kQ3AxisZ;
  517.     } else {
  518.         fromAxis = kQ3AxisX;
  519.     }
  520.  
  521.     /*
  522.      *  Compute the length of the diagonal of the bounding box.
  523.      *
  524.      *  The hither and yon planes are adjusted so that the
  525.       *  diagonal of the bounding box is 7/8 the size of the
  526.       *  minimum dimension of the view frustum. The diagonal is used instead
  527.       *  of the maximum size (in x, y, or z) so that when you rotate
  528.       *  the object, the corners don't get clipped out.
  529.       */
  530.     Q3Point3D_Subtract(
  531.         &viewBBox.max,
  532.         &viewBBox.min,
  533.         &diagonalVector);
  534.  
  535.     maxDimension    =    Q3Vector3D_Length(&diagonalVector);
  536.     maxDimension    *=    8.0 / 7.0;
  537.     
  538.     ratio = 1.0 / maxDimension;
  539.             
  540.     *documentGroupScale = ratio;
  541.     
  542.     Q3Camera_GetPlacement(camera, &placement);
  543.  
  544.     Q3Point3D_Subtract(
  545.         &placement.cameraLocation,
  546.         &placement.pointOfInterest,
  547.         &viewVector);
  548.         
  549.     viewDistance = Q3Vector3D_Length(&viewVector);
  550.     
  551.     Q3Vector3D_Normalize(&viewVector, &normViewVector);
  552.     
  553.     Q3Vector3D_Scale(&normViewVector, 
  554.                      viewDistance - ratio * maxDimension/2.0,
  555.                      &eyeToFrontClip);
  556.                     
  557.     Q3Vector3D_Scale(&normViewVector, 
  558.                     viewDistance + ratio * maxDimension/2.0,
  559.                     &eyeToBackClip);
  560.  
  561.     hither     = Q3Vector3D_Length(&eyeToFrontClip);
  562.     yon     = Q3Vector3D_Length(&eyeToBackClip);
  563.     
  564.     fieldOfView = 2 * atan((ratio * maxDimension/2.0)/hither);
  565.  
  566.     range.hither                 = hither;
  567.     range.yon                     = yon;
  568.  
  569.     Q3Camera_SetRange(camera, &range);
  570.  
  571.     Q3ViewAngleAspectCamera_SetFOV(
  572.         camera, fieldOfView);
  573.  
  574.     Q3ViewAngleAspectCamera_SetAspectRatio(
  575.         camera, (float) winWidth / (float) winHeight);
  576.  
  577.     Q3Object_Dispose(camera);
  578.     
  579.     return( *documentGroupCenter );
  580. }
  581.  
  582.